﻿#include "HttpConnection.h"
#include "LogicSystem.h"

HttpConnection::HttpConnection(boost::asio::io_context& ioc):_socket(ioc) {}

void HttpConnection::Start() 
{
	auto self = shared_from_this();
	//async_read(AsyncReadStream& stream,DynamicBuffer& buffer,basic_parser<isRequest>& parser,ReadHandler&& handler
	//第一个参数为异步可读的数据流，可以理解为socket.
	//第二个参数为一个buffer，用来存储接受的数据，因为http可接受文本，图像，音频等多种资源文件，所以是Dynamic动态类型的buffer。
	//第三个参数是请求参数，我们一般也要传递能接受多种资源类型的请求参数。
	//第四个参数为回调函数，接受成功或者失败，都会触发回调函数，用lambda表达式就可以了。
	http::async_read(_socket, _buffer, _request, [self](beast::error_code ec,
		std::size_t bytes_transferred) {
			try {
				if (ec) {
					std::cout << "http read err is" << ec.what() << std::endl;
					return;
				}
				//处理读到的数据
				boost::ignore_unused(bytes_transferred);
				self->HandleReq();
				self->CheckDeadline();
			}
			catch (std::exception& exp) {
				std::cout << "http read exception is" << exp.what() << std::endl;
			}
		});
}


unsigned char ToHex(unsigned char x) {
	return x > 9 ? x + 55 : x + 48;
}

unsigned char FromHex(unsigned char x)
{
	unsigned char y;
	if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
	else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
	else if (x >= '0' && x <= '9') y = x - '0';
	else assert(0);
	return y;
}

std::string UrlEncode(const std::string& str)//编码
{
	std::string strTemp = "";
	size_t length = str.length();
	for (size_t i = 0; i < length; i++)
	{
		//判断是否仅有数字和字母构成
		if (isalnum((unsigned char)str[i]) ||
			(str[i] == '-') ||
			(str[i] == '_') ||
			(str[i] == '.') ||
			(str[i] == '~'))
			strTemp += str[i];
		else if (str[i] == ' ') //为空字符
			strTemp += "+";
		else
		{
			//其他字符需要提前加%并且高四位和低四位分别转为16进制
			strTemp += '%';
			strTemp += ToHex((unsigned char)str[i] >> 4);
			strTemp += ToHex((unsigned char)str[i] & 0x0F);
		}
	}
	return strTemp;
}

std::string UrlDecode(const std::string& str)//解码
{
	std::string strTemp = "";
	size_t length = str.length();
	for (size_t i = 0; i < length; i++)
	{
		//还原+为空
		if (str[i] == '+') strTemp += ' ';
		//遇到%将后面的两个字符从16进制转为char再拼接
		else if (str[i] == '%')
		{
			assert(i + 2 < length);
			unsigned char high = FromHex((unsigned char)str[++i]);
			unsigned char low = FromHex((unsigned char)str[++i]);
			strTemp += high * 16 + low;
		}
		else strTemp += str[i];
	}
	return strTemp;
}

void HttpConnection::PreParseGetParam() {
	// 提取 URI  localhost:8080/get_test?key1=value1&key2=value2
	auto uri = _request.target();
	// 查找查询字符串的开始位置（即 '?' 的位置）  
	auto query_pos = uri.find('?');
	if (query_pos == std::string::npos) {
		_get_url = uri;
		return;
	}

	_get_url = uri.substr(0, query_pos);//  localhost:8080/get_test
	std::string query_string = uri.substr(query_pos + 1);// key1=value1&key2=value2
	std::string key;
	std::string value;
	size_t pos = 0;
	while ((pos = query_string.find('&')) != std::string::npos) {
		auto pair = query_string.substr(0, pos);
		size_t eq_pos = pair.find('=');
		if (eq_pos != std::string::npos) {
			key = UrlDecode(pair.substr(0, eq_pos)); 
			value = UrlDecode(pair.substr(eq_pos + 1));
			_get_params[key] = value;
		}
		query_string.erase(0, pos + 1);
	}
	// 处理最后一个参数对（如果没有 & 分隔符）  
	if (!query_string.empty()) {
		size_t eq_pos = query_string.find('=');
		if (eq_pos != std::string::npos) {
			key = UrlDecode(query_string.substr(0, eq_pos));
			value = UrlDecode(query_string.substr(eq_pos + 1));
			_get_params[key] = value;
		}
	}
}

void HttpConnection::HandleReq() {
	//设置版本•	将响应的 HTTP 版本设置为与请求的版本一致。
	_response.version(_request.version());
	
	_response.keep_alive(false);//处理完请求后关闭连接
	if (_request.method() == http::verb::get) {//检查请求方法是否为 GET
		PreParseGetParam();
		bool success = LogicSystem::GetInstance()->HandleGet(_get_url,shared_from_this());
		if (!success) {
			//如果没有处理成功，返回404
			_response.result(http::status::not_found);
			
			_response.set(http::field::content_type, "text/plain");//响应的内容类型为纯文本
			
			beast::ostream(_response.body()) << "url Not Found\r\n";//写入响应体内容
			WriteResponse();
			return;
		}/*在 HandleReq 方法中，当处理 GET 请求失败（例如 URL 未找到）时，设置响应的状态为 404 Not Found，并通过这行代码明确告知客户端，响应体的内容是纯文本格式。随后，响应体中写入了 "url Not Found&#x0a;"，这与 Content-Type: text/plain 一致。*/
		_response.result(http::status::ok);
		_response.set(http::field::server, "GateServer");
		WriteResponse();
		return;
	}

	if (_request.method() == http::verb::post) {
		bool success = LogicSystem::GetInstance()->HandlePost(_request.target(), shared_from_this());
		if (!success) {
			//如果没有处理成功，返回404
			_response.result(http::status::not_found);

			_response.set(http::field::content_type, "text/plain");//响应的内容类型为纯文本

			beast::ostream(_response.body()) << "url Not Found\r\n";//写入响应体内容
			WriteResponse();
			return;
		}/*在 HandleReq 方法中，当处理 GET 请求失败（例如 URL 未找到）时，设置响应的状态为 404 Not Found，并通过这行代码明确告知客户端，响应体的内容是纯文本格式。随后，响应体中写入了 "url Not Found&#x0a;"，这与 Content-Type: text/plain 一致。*/
		_response.result(http::status::ok);
		_response.set(http::field::server, "GateServer");
		WriteResponse();
		return;
	}
}

void HttpConnection::WriteResponse() {
	auto self = shared_from_this();
	_response.content_length(_response.body().size());
	//异步写入响应
	http::async_write(_socket, _response, [self](beast::error_code ec,
		std::size_t bytes_transferred) {
			self->_socket.shutdown(tcp::socket::shutdown_send, ec);
			self->_deadline.cancel();
		});
}

void HttpConnection::CheckDeadline() {
	auto self = shared_from_this();
	_deadline.async_wait([self](beast::error_code ec) {
		if (!ec) {
			self->_socket.close(ec);
			self->_deadline.cancel();
		}
		});
}